Skip to content

Update install script for home-directory defaults#341

Merged
kindermax merged 6 commits intomasterfrom
codex/implement-issue-121
Apr 26, 2026
Merged

Update install script for home-directory defaults#341
kindermax merged 6 commits intomasterfrom
codex/implement-issue-121

Conversation

@kindermax
Copy link
Copy Markdown
Collaborator

@kindermax kindermax commented Apr 25, 2026

Summary

  • Move the default installer target to $HOME/.lets/bin and switch the script to Bash.
  • Keep positional version support, add LETS_VERSION precedence, and preserve Amp-style PATH symlink/profile handling.
  • Update installation and development docs, changelog, and the development install command to match the new layout.

Testing

  • bash -n install.sh
  • Focused installer checks against a fake release flow for default install, PATH reuse, profile editing, and LETS_VERSION precedence.
  • lets fmt
  • go test ./...
  • lets build

Summary by Sourcery

Update the installer to use a home-directory–scoped layout by default and align documentation, development workflow, and changelog with the new installation behavior.

New Features:

  • Add LETS_HOME configuration and a default install location at $HOME/.lets/bin for the lets binary.
  • Support selecting the install version via LETS_VERSION with precedence over a positional tag argument.
  • Automatically create user PATH symlinks and update shell profiles so lets is available on the PATH after installation.

Bug Fixes:

  • Detect and abort when an old non-Homebrew /usr/local/bin/lets installation is present to avoid unsafe upgrades.

Enhancements:

  • Port the install script from POSIX sh to Bash and simplify its interface by removing the -b bindir flag.
  • Update development commands and build-and-install workflow to install lets-dev into user-writable locations under $HOME/.local/bin.
  • Clarify binary upgrade behavior comments around supported installer-managed paths.

Documentation:

  • Revise installation docs to describe the new $HOME/.lets/bin default, LETS_VERSION/LETS_HOME usage, and automated PATH handling.
  • Update development and changelog documentation to reflect the new install paths and behavior.

@sourcery-ai
Copy link
Copy Markdown

sourcery-ai Bot commented Apr 25, 2026

Reviewer's Guide

Installer now defaults to installing lets into $HOME/.lets/bin via a Bash-based script, adds LETS_HOME/LETS_VERSION support plus PATH/symlink/profile management, blocks unsafe legacy /usr/local/bin installs, and aligns docs, dev workflow, and changelog with the new layout.

Sequence diagram for the updated installer and PATH/profile behavior

sequenceDiagram
  actor User
  participant Shell
  participant Installer as install_sh
  participant GitHub as GitHub_releases
  participant FS as Filesystem

  User->>Shell: curl -fsSL ... | bash
  Shell->>Installer: execute script

  Installer->>Installer: parse_args
  Installer->>Installer: resolve TAG
  Note over Installer: LETS_VERSION overrides positional tag

  Installer->>Installer: check_old_usr_local_install
  Installer->>FS: check /usr/local/bin/lets
  alt Homebrew-managed lets
    Installer-->>User: log_info Homebrew install detected
  else legacy non-Homebrew lets
    Installer-->>User: log_crit remove old /usr/local/bin/lets
    Installer-->>Shell: exit 1
    Installer-->>Shell: return
  end

  Installer->>Installer: get_binaries
  Installer->>Installer: tag_to_version
  Installer->>Installer: uname_os / uname_arch

  Installer->>GitHub: download tarball and checksum
  GitHub-->>Installer: tarball and checksum
  Installer->>Installer: hash_sha256_verify
  Installer->>FS: untar and install to $HOME/.lets/bin
  Installer-->>User: log_info installed $HOME/.lets/bin/lets

  Installer->>Installer: update_shell_profile
  Installer->>Installer: try_symlink_in_path
  loop preferred_dirs
    Installer->>FS: ensure dir exists
    Installer->>FS: ln -sf BIN_DIR/lets -> dir/lets
    alt symlink_created
      Installer-->>User: log_info created symlink
      Note over Installer: break
    end
  end
  alt symlink_created_in_preferred_dir
    Installer-->>User: lets available via existing PATH entry
  else no_preferred_dir_in_PATH
    Installer->>FS: mkdir -p $HOME/.local/bin
    Installer->>FS: ln -sf BIN_DIR/lets -> $HOME/.local/bin/lets
    Installer->>Installer: detect shell and profile file
    alt ~/.local/bin already in PATH
      Installer-->>User: log_info existing PATH config
      Installer-->>User: print one-shot PATH export
    else not yet configured
      alt interactive_shell
        Installer-->>User: prompt to add ~/.local/bin to PATH
        User-->>Installer: answer y/n
        alt user_accepts
          Installer->>FS: append PATH export to shell_profile
          Installer-->>User: log_info PATH updated
        else user_declines
          Installer-->>User: log_info skipped profile change
        end
      else non_interactive
        Installer->>FS: append PATH export to shell_profile
        Installer-->>User: log_info PATH updated
      end
    end
  end

  Installer-->>Shell: exit 0
  Shell-->>User: lets command ready in PATH
Loading

Flow diagram for PATH, symlink, and profile management in the installer

flowchart TD
  A[start update_shell_profile] --> B[try_symlink_in_path lets]
  B -->|symlink_created_in_existing_preferred_dir| Z[finish update_shell_profile]
  B -->|no_symlink_created| C[ensure $HOME/.local/bin exists]

  C --> D[create symlink $HOME/.local/bin/lets -> BIN_DIR/lets]
  D -->|success| E[detect shell and OS]
  D -->|failure| D1[log_err and print manual PATH instructions]
  D1 --> Z

  E --> F{shell type}
  F -->|zsh| G[set shell_profile=$HOME/.zshrc
set path_export=export PATH='$HOME/.local/bin:$PATH']
  F -->|bash_on_Darwin| H[prefer .bash_profile then .bashrc
set path_export]
  F -->|bash_other_OS| I[prefer .bashrc then .bash_profile
set path_export]
  F -->|fish| J[set shell_profile=$HOME/.config/fish/config.fish
set path_export=fish_add_path '$HOME/.local/bin']
  F -->|other| K[log_err unknown shell
print manual PATH instructions]
  K --> Z

  G --> L[continue with chosen shell_profile]
  H --> L
  I --> L
  J --> L

  L --> M{shell_profile already adds .local/bin?}
  M -->|yes| N[log_info PATH already configured
print one-shot PATH export]
  N --> Z

  M -->|no| O{stdin is interactive?}
  O -->|no| P[append PATH export block to shell_profile]
  P --> Q[log_info PATH updated and print one-shot export]
  Q --> Z

  O -->|yes| R[prompt user: add ~/.local/bin to PATH?]
  R -->|user_yes| S[create shell_profile if missing
append PATH export block]
  S --> Q
  R -->|user_no| T[log_info skipped profile change
print manual PATH instructions]
  T --> Z

  Z[end update_shell_profile]
Loading

File-Level Changes

Change Details Files
Switch installer to Bash, default installation into $HOME/.lets/bin, and add LETS_VERSION precedence.
  • Change shebang to use Bash and introduce LETS_HOME/LETTS_VERSION variables with defaults for the install location and version selection.
  • Simplify CLI flags by removing bindir (-b) handling and compute the TAG from positional argument with LETS_VERSION taking precedence.
  • Install downloaded binaries into BIN_DIR derived from LETS_HOME rather than the previous BINDIR default.
install.sh
Add safety check for legacy /usr/local/bin installs and implement PATH exposure via symlinks and shell profile updates.
  • Detect and abort on old non-Homebrew /usr/local/bin/lets binaries before proceeding with installation.
  • Add helpers to resolve symlink targets and detect Homebrew installs to avoid interfering with them.
  • Implement logic to create symlinks from $HOME/.lets/bin/lets into user PATH directories (prefer ~/.local/bin, ~/bin, ~/.bin) or add ~/.local/bin to PATH in the user’s shell profile when needed.
install.sh
Update user and developer documentation to describe the new installer behavior and user-local PATH recommendations.
  • Change installation examples to use curl
bash with $HOME/.lets/bin as the default target and describe LETS_HOME/LETS_VERSION usage and PATH/symlink behavior.
  • Adjust manual installation guidance to recommend user-local PATH directories like $HOME/.local/bin instead of system-wide locations.
  • Update upgrade instructions to use the new installer behavior without specifying a bindir.
  • Align development build-and-install flow with user-local bin directories and remove sudo requirement.
    • Change lets-dev build command to use ./cmd/lets as the entry point and install into $HOME/.local/bin by default instead of /usr/local/bin.
    • Create the target directory before installation, drop sudo mv, and adjust messaging to reflect the new default path.
    • Update build-and-install examples and defaults in lets.yaml to use ~/.local/bin.
    docs/docs/development.md
    lets.yaml
    Document installer behavior in changelog and refine self-upgrade comment. internal/upgrade/upgrade.go
    docs/docs/changelog.md

    Possibly linked issues


    Tips and commands

    Interacting with Sourcery

    • Trigger a new review: Comment @sourcery-ai review on the pull request.
    • Continue discussions: Reply directly to Sourcery's review comments.
    • Generate a GitHub issue from a review comment: Ask Sourcery to create an
      issue from a review comment by replying to it. You can also reply to a
      review comment with @sourcery-ai issue to create an issue from it.
    • Generate a pull request title: Write @sourcery-ai anywhere in the pull
      request title to generate a title at any time. You can also comment
      @sourcery-ai title on the pull request to (re-)generate the title at any time.
    • Generate a pull request summary: Write @sourcery-ai summary anywhere in
      the pull request body to generate a PR summary at any time exactly where you
      want it. You can also comment @sourcery-ai summary on the pull request to
      (re-)generate the summary at any time.
    • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
      request to (re-)generate the reviewer's guide at any time.
    • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
      pull request to resolve all Sourcery comments. Useful if you've already
      addressed all the comments and don't want to see them anymore.
    • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
      request to dismiss all existing Sourcery reviews. Especially useful if you
      want to start fresh with a new review - don't forget to comment
      @sourcery-ai review to trigger a new review!

    Customizing Your Experience

    Access your dashboard to:

    • Enable or disable review features such as the Sourcery-generated pull request
      summary, the reviewer's guide, and others.
    • Change the review language.
    • Add, remove or edit custom review instructions.
    • Adjust other review settings.

    Getting Help

    Copy link
    Copy Markdown

    @sourcery-ai sourcery-ai Bot left a comment

    Choose a reason for hiding this comment

    The reason will be displayed to describe this comment to others. Learn more.

    Hey - I've found 1 issue, and left some high level feedback:

    • The new interactive prompt in update_shell_profile (read -r -p ...) will block non-interactive/CI installs; consider adding a flag or environment variable to force non-interactive behavior and skip prompts safely.
    • The dir_in_path helper uses a simple grep on :$PATH: which can still mis-detect directories with shared prefixes (e.g. /home/user/bin vs /home/user/bin-extra); consider normalizing the paths and comparing components explicitly.
    • In update_shell_profile, the logic for detecting whether ~/.local/bin is already on PATH is regex-based and shell-specific; factoring this into a small, testable helper (reused for dir_in_path) would reduce duplication and make edge-case handling clearer.
    Prompt for AI Agents
    Please address the comments from this code review:
    
    ## Overall Comments
    - The new interactive prompt in `update_shell_profile` (`read -r -p ...`) will block non-interactive/CI installs; consider adding a flag or environment variable to force non-interactive behavior and skip prompts safely.
    - The `dir_in_path` helper uses a simple `grep` on `:$PATH:` which can still mis-detect directories with shared prefixes (e.g. `/home/user/bin` vs `/home/user/bin-extra`); consider normalizing the paths and comparing components explicitly.
    - In `update_shell_profile`, the logic for detecting whether `~/.local/bin` is already on `PATH` is regex-based and shell-specific; factoring this into a small, testable helper (reused for `dir_in_path`) would reduce duplication and make edge-case handling clearer.
    
    ## Individual Comments
    
    ### Comment 1
    <location path="install.sh" line_range="212-219" />
    <code_context>
    +  log_crit "then run this installer again"
    +  exit 1
    +}
    +dir_in_path() {
    +  check_dir=$1
    +
    +  if [ -d "$check_dir" ]; then
    +    check_dir=$(cd "$check_dir" >/dev/null 2>&1 && pwd) || return 1
    +  fi
    +
    +  echo ":$PATH:" | grep -q ":$check_dir:"
    +}
    +try_symlink_in_path() {
    </code_context>
    <issue_to_address>
    **issue (bug_risk):** Use fixed-string grep to avoid regex matching issues when checking if a directory is in PATH.
    
    Without `-F`, characters like `.` in `$check_dir` are interpreted as regex, so `/home/user/.local/bin` could incorrectly match `/home/userXlocal/bin`. Using fixed-string grep makes the PATH check accurate, e.g.:
    
    ```bash
    echo ":$PATH:" | grep -F -q ":$check_dir:"
    ```
    </issue_to_address>

    Sourcery is free for open source - if you like our reviews please consider sharing them ✨
    Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

    Comment thread install.sh
    Comment on lines +212 to +219
    dir_in_path() {
    check_dir=$1

    if [ -d "$check_dir" ]; then
    check_dir=$(cd "$check_dir" >/dev/null 2>&1 && pwd) || return 1
    fi

    echo ":$PATH:" | grep -q ":$check_dir:"
    Copy link
    Copy Markdown

    Choose a reason for hiding this comment

    The reason will be displayed to describe this comment to others. Learn more.

    issue (bug_risk): Use fixed-string grep to avoid regex matching issues when checking if a directory is in PATH.

    Without -F, characters like . in $check_dir are interpreted as regex, so /home/user/.local/bin could incorrectly match /home/userXlocal/bin. Using fixed-string grep makes the PATH check accurate, e.g.:

    echo ":$PATH:" | grep -F -q ":$check_dir:"

    @kindermax kindermax merged commit 93ca4a7 into master Apr 26, 2026
    5 checks passed
    @kindermax kindermax deleted the codex/implement-issue-121 branch April 26, 2026 09:09
    Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

    Labels

    None yet

    Projects

    None yet

    Development

    Successfully merging this pull request may close these issues.

    1 participant